package com.touchapk.javafx;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Iterator;

import javafx.application.Platform;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.Tooltip;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.util.Callback;

import org.fxmisc.richtext.CodeArea;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;

import com.sun.javafx.robot.FXRobot;
import com.sun.javafx.robot.FXRobotFactory;
import com.touchapk.core.Events;
import com.touchapk.core.Job;
import com.touchapk.util.FileUtil;

/**
 * @description
 * @author yangkeyun
 * @email coyun@qq.com
 * @date 2016年8月13日
 * @version V1.0
 */
public class FileTreeCell extends TreeCell<File>{
	

	private TabPane tabPane;
	private MainController mainController;
	
	public FileTreeCell(TreeView<File> treeView,TabPane tabPane, MainController mainController){
		
		this.tabPane=tabPane;
		this.mainController=mainController;
		ContextMenu addMenu = new ContextMenu();
		
		MenuItem addMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.new.project"));
		addMenuItem.setGraphic(new ImageView(Main.class.getResource("prj_obj.gif").toExternalForm()));
		MenuItem refreshMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.refresh"));
		
		refreshMenuItem.setGraphic(new ImageView(Main.class.getResource("refresh_tab.gif").toExternalForm()));
		addMenu.getItems().add(addMenuItem);
		addMenu.getItems().add(refreshMenuItem);
		
		addMenuItem.setOnAction(new EventHandler() {
			public void handle(Event t) {
				FXMLDialog npd = mainController.getNewProjectDialog();
				npd.setResizable(false);
				npd.show();
			}
		});
		
		refreshMenuItem.setOnAction(new EventHandler() {
			public void handle(Event t) {
				treeView.setCellFactory(new Callback<TreeView<File>, TreeCell<File>>() {
					@Override
					public TreeCell<File> call(TreeView<File> arg0) {
						return new FileTreeCell(treeView,tabPane,mainController);
					}
				});
			}
		});
		setContextMenu(addMenu);
	}

	@Override
	protected void updateItem(File f, boolean empty) {
		super.updateItem(f, empty);
		if (empty) {
			setText(null);
			setGraphic(null);
		} else {
			
			ContextMenu addMenu = new ContextMenu();
		
			setText(f.getName());
			
			if (f.isDirectory()) {
				
				MenuItem addFolderMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.new.folder"));
				addFolderMenuItem.setGraphic(new ImageView(Main.class.getResource("fldr_obj.gif").toExternalForm()));
				addMenu.getItems().add(addFolderMenuItem);
				
				addFolderMenuItem.setOnAction(new EventHandler() {
					public void handle(Event t) {
						
						mainController.getNewController().setMsg(mainController.getI18nBundle().getString("menu.folder.name"));
						mainController.getNewController().setPath(f.getAbsolutePath());
						FXMLDialog ddialog = mainController.getNewDialog();
						ddialog.setTitle("create");
						
						mainController.call(new Callback() {
							@Override
							public Object call(Object param) {
								File fFile=new File(f.getAbsolutePath()+"\\"+param);
								if(!fFile.exists()){
									fFile.mkdirs();
								}
								FileTreeItem fitem = new FileTreeItem(fFile,false);
								
								getTreeItem().getChildren().add(0, fitem);
							
								return null;
							}
						});
						ddialog.show();
					}
				});
				
				MenuItem addFileMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.new.file"));
				addFileMenuItem.setGraphic(new ImageView(Main.class.getResource("file_obj.gif").toExternalForm()));
				addMenu.getItems().add(addFileMenuItem);
				
				addFileMenuItem.setOnAction(new EventHandler() {
					public void handle(Event t) {
						
						mainController.getNewController().setMsg(mainController.getI18nBundle().getString("menu.file.name"));
						mainController.getNewController().setPath(f.getAbsolutePath());
						FXMLDialog ddialog = mainController.getNewDialog();
						ddialog.setTitle("create");
						
						mainController.call(new Callback() {
							@Override
							public Object call(Object param) {
								File fFile=new File(f.getAbsolutePath()+"\\"+param);
								if(!fFile.exists()){
									try {
										fFile.createNewFile();
										FileOutputStream out=new FileOutputStream(fFile);
										BufferedWriter rd = new BufferedWriter(new OutputStreamWriter(out,"utf-8"));
										 rd.write("-- new file");
										 out.flush();
										 rd.close();
										 out.close();
									} catch (IOException e) { }
								}
								FileTreeItem fitem = new FileTreeItem(fFile,false);
								getTreeItem().getChildren().add(fitem);
								
								return null;
							}
						});
						ddialog.show();
					}
				});
				
				MenuItem deleteMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.delete"));
				deleteMenuItem.setGraphic(new ImageView(Main.class.getResource("delete.gif").toExternalForm()));
				
				addMenu.getItems().add(deleteMenuItem);
				if(f.getParentFile().getAbsolutePath().equals(this.mainController.getPath())){
					setGraphic(new ImageView(Main.class.getResource("prj_obj.gif").toExternalForm()));
					deleteMenuItem.setOnAction(new EventHandler() {
						public void handle(Event t) {
							
							mainController.getDeleController().setMsg(mainController.getI18nBundle().getString("delete.project.msg"));
							FXMLDialog ddialog = mainController.getDeleDialog();
							ddialog.setTitle("delete");
							
							mainController.call(new Callback() {
								@Override
								public Object call(Object param) {
									FileUtil.deleteDirectory(f.getAbsolutePath());
									if(getTreeItem().getParent()!=null&&getTreeItem().getParent().getChildren()!=null){
										getTreeItem().getParent().getChildren().remove(getTreeItem());//在目录中删除自己
									}
									return null;
								}
							});
							ddialog.show();
						}
					});
					
				}else{
					setGraphic(new ImageView(Main.class.getResource("fldr_obj.gif").toExternalForm()));
					deleteMenuItem.setOnAction(new EventHandler() {
						public void handle(Event t) {
							
							mainController.getDeleController().setMsg(mainController.getI18nBundle().getString("delete.folder.msg"));
							FXMLDialog ddialog = mainController.getDeleDialog();
							ddialog.setTitle("delete");
							
							mainController.call(new Callback() {
								@Override
								public Object call(Object param) {
									FileUtil.deleteDirectory(f.getAbsolutePath());
									if(getTreeItem().getParent()!=null&&getTreeItem().getParent().getChildren()!=null){
										getTreeItem().getParent().getChildren().remove(getTreeItem());//在目录中删除自己
									}
									return null;
								}
							});
							ddialog.show();
							
						}
					});
				}
				
			} else {
				
				String fileName = f.getName();
				
				
				MenuItem openMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.file.open"));
				openMenuItem.setGraphic(new ImageView(Main.class.getResource("edit.png").toExternalForm()));
				addMenu.getItems().add(openMenuItem);
				
				
				if (fileName.endsWith(".lua")) {
					addMenu.getItems().addAll(getLuaMenuItem(f));
				}
				
				
				openMenuItem.setOnAction(new EventHandler() {
					public void handle(Event t) {
						openFile(f);
					}
				});
				
			
				MenuItem deleteMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.delete"));
				deleteMenuItem.setGraphic(new ImageView(Main.class.getResource("delete.gif").toExternalForm()));
				
				if(!".project".equals(fileName)){
					addMenu.getItems().add(deleteMenuItem);
				}
				
				deleteMenuItem.setOnAction(new EventHandler() {
					public void handle(Event t) {
						mainController.getDeleController().setMsg(mainController.getI18nBundle().getString("delete.file.msg"));
						FXMLDialog ddialog = mainController.getDeleDialog();
						ddialog.setTitle("delete");
						
						mainController.call(new Callback() {
							@Override
							public Object call(Object param) {
								
								
								Tab myTab=null;
								Iterator<Tab> iterator=tabPane.getTabs().iterator();
								while(iterator.hasNext()){
									Tab tab=iterator.next();
									if(f.getAbsolutePath().equals(tab.getTooltip().getText())){	
										myTab=tab;
										break;
									}
								}
								if(myTab!=null){
									tabPane.getTabs().remove(myTab);
								}
								
								FileUtil.deleteFile(f.getAbsolutePath());
								if(getTreeItem().getParent()!=null&&getTreeItem().getParent().getChildren()!=null){
									getTreeItem().getParent().getChildren().remove(getTreeItem());//在目录中删除自己
								}
								return null;
							}
						});
						ddialog.show();
					}
				});
				
				
					setOnMouseClicked(new EventHandler<MouseEvent>() {
					    @Override
					    public void handle(MouseEvent mouseEvent) {
					        if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){
					            if(mouseEvent.getClickCount() == 2){
					            		openFile(f);
					            }
					        }
					    }
					});
				
				
				if (fileName != null) {
					
					if (fileName.endsWith(".lua")) {
						
						setGraphic(getLuaRunStatus(f));
						
					} else if (fileName.endsWith(".png")
							|| fileName.endsWith(".gif")
							|| fileName.endsWith(".jpg")) {
						setGraphic(new ImageView(
								Main.class.getResource("image_obj.gif").toExternalForm()));
					} else {
						setGraphic(new ImageView(
								Main.class.getResource("file_obj.gif").toExternalForm()));
					}
				}
			}
			
			setContextMenu(addMenu);
			
		}
	}
	
	class LuaStatus {
		public boolean isRunning;
		
		public Thread singleThread;
		
		private Callback callback;
		public void setCallback(Callback callback){
			this.callback=callback;
		}
		public Callback getCallback(){
			return this.callback;
		}
	}
	
	
	
	
	public AnchorPane getLuaRunStatus(File f){
		
		LuaStatus luaStatus=MainController.luaStatusMap.get(f.getAbsolutePath());
		
		if(luaStatus==null){
			MainController.luaStatusMap.put(f.getAbsolutePath(), new LuaStatus());
		}
		
		AnchorPane anchorPane=new AnchorPane();
		
		ImageView img = new ImageView(Main.class.getResource("lua.png").toExternalForm());
		
		anchorPane.getChildren().add(img);
		
		ImageView btn= new ImageView(Main.class.getResource("nav_stop.gif").toExternalForm());
		
		if(luaStatus!=null){
			if(luaStatus.isRunning){
				anchorPane.getChildren().add(btn);
			}
			luaStatus.setCallback(new Callback() {
				public Object call(Object param) {
					if((boolean)param){
						luaStatus.isRunning=false;
						Platform.runLater(new Runnable() {
							@Override
							public void run() {
								anchorPane.getChildren().remove(btn);
							}
						});
						if(luaStatus.singleThread!=null&&luaStatus.singleThread.isAlive()){
							luaStatus.singleThread.stop();
							luaStatus.singleThread=null;
						}
					}else{
						Platform.runLater(new Runnable() {
							@Override
							public void run() {
								anchorPane.getChildren().add(btn);
							}
						});
						luaStatus.isRunning=true;
					}
					return null;
				}
				
			});
		}
		
		btn.setLayoutX(20);
		
		btn.setOnMouseMoved(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent e) {
				btn.setOpacity(0.2);
				Platform.runLater(new Runnable() {
					@Override
					public void run() {
						try {
							Thread.sleep(50);
						} catch (InterruptedException e) {}
							btn.setOpacity(1);
						}
				});
			}
		});
		
		btn.setOnMouseClicked(new EventHandler<MouseEvent>() {
			@Override
			public void handle(MouseEvent e) {
				if(luaStatus!=null&&luaStatus.isRunning){
					luaStatus.getCallback().call(true);//结束命令
				}
			}
		}); 
		
		return anchorPane;
	}
	
	public void openFile(File f){
		
		ContextMenu contentMenu = new ContextMenu();
		
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				String fileName = f.getName();

				boolean isLua = false;
				if (fileName.endsWith(".lua")) {
					isLua = true;
				}
				
				LuaKeywords luaKeywords = new LuaKeywords(f.getAbsolutePath(),isLua);
				
				contentMenu.getItems().addAll(getMenuItem(luaKeywords.getCodeArea()));
				
				if(isLua){
					contentMenu.getItems().addAll(getLuaMenuItem(f));
				}
				
				Tab myTab = new Tab(fileName);

				boolean isExit = false;
				Iterator<Tab> iterator = tabPane.getTabs().iterator();
				while (iterator.hasNext()) {
					Tab tab = iterator.next();
					if (f.getAbsolutePath().equals(tab.getTooltip().getText())) {
						isExit = true;
						myTab = tab;
						break;
					}
				}

				if (isLua) {
					myTab.setGraphic(new ImageView(Main.class.getResource("lua.png").toExternalForm()));
				} else {
					myTab.setGraphic(new ImageView(Main.class.getResource("file_obj.gif").toExternalForm()));
				}
				myTab.setTooltip(new Tooltip(f.getAbsolutePath()));
				StackPane stack = luaKeywords.getStackPane();
				
				myTab.setContent(stack);

			
				
				luaKeywords.getCodeArea().setOnMousePressed(
						new EventHandler<MouseEvent>() {
							@Override
							public void handle(MouseEvent e) {
								if (e.getButton() == MouseButton.SECONDARY) {
									contentMenu.show(stack, e.getScreenX(),e.getScreenY());
								}
							}
						});
				
				
				if (!isExit) {
					tabPane.getTabs().add(myTab);
				}

				SingleSelectionModel<Tab> selectionModel = tabPane
						.getSelectionModel();
				selectionModel.select(myTab);
				int hashcode = luaKeywords.getCodeArea().getText().hashCode();

				Tab myTab1 = myTab;

				luaKeywords
						.getCodeArea()
						.richChanges()
						.filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
						.subscribe(
								change -> {
									int hash = luaKeywords.getCodeArea().getText().hashCode();
									if (hashcode != hash) {
										if (myTab1.getText().equals(fileName)) {
											myTab1.setText("*" + fileName);
										}
									} else {
										if (!myTab1.getText().equals(fileName)) {
											myTab1.setText(fileName);
										}
									}
								});

				luaKeywords.getCodeArea().setOnKeyPressed(
						new EventHandler<KeyEvent>() {
							@Override
							public void handle(KeyEvent event) {
								
								luaKeywords.call(event);

								if (event.isControlDown()
										&& "S".equals(event.getCode().toString())) {
									if (!myTab1.getText().equals(fileName)) {
										myTab1.setText(fileName);
										int hash = luaKeywords.getCodeArea().getText().hashCode();
									}
								}
								
								if (event.isShiftDown()&& "ENTER".equals(event.getCode().toString())) {
									
									FXRobot robot = FXRobotFactory.createRobot(tabPane.getParent().getScene());  
									robot.keyPress(KeyCode.END);  
									robot.keyPress(KeyCode.ENTER);  
				
								}
								
							}
						});
			}
		});
	}
	
	
	public MenuItem[] getMenuItem(CodeArea CodeArea){
		
		MenuItem copyaMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.edite.copy"));
		copyaMenuItem.setGraphic(new ImageView(Main.class.getResource("copy_edit.gif").toExternalForm()));
		MenuItem pasteMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.edite.paste"));
		pasteMenuItem.setGraphic(new ImageView(Main.class.getResource("paste_edit.gif").toExternalForm()));
		
		copyaMenuItem.setOnAction(new EventHandler() {
			public void handle(Event t) {
				CodeArea.copy();
			}
		});
		
		pasteMenuItem.setOnAction(new EventHandler() {
			public void handle(Event t) {
				CodeArea.paste();
			}
		});

		return new MenuItem[]{copyaMenuItem,pasteMenuItem};
	}
	
	
	public MenuItem[] getLuaMenuItem(File f){
		
		MenuItem runLuaMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.run.lua"));
		
		runLuaMenuItem.setGraphic(new ImageView(Main.class.getResource("lrun_obj.gif").toExternalForm()));

		MenuItem runLuaForAppMenuItem = new MenuItem(mainController.getI18nBundle().getString("menu.run.app"));
		
		runLuaForAppMenuItem.setGraphic(new ImageView(Main.class.getResource("lrun_obj.gif").toExternalForm()));
		
		runLuaMenuItem.setOnAction(new LuaEventHandler(f,false));
		
		runLuaForAppMenuItem.setOnAction(new LuaEventHandler(f,true));

		return new MenuItem[]{runLuaMenuItem,runLuaForAppMenuItem};
	}
	
	
	 class LuaEventHandler implements EventHandler{
		 
		 
		private File f;
		private boolean isApp;
		private LuaStatus luaStatus ;
		private String projcetPath;
		private String currFilePath;
		public LuaEventHandler(File f,boolean isApp){
			
			luaStatus = MainController.luaStatusMap.get(f.getAbsolutePath());
			
			this.f=f;
			this.isApp=isApp;
			
			currFilePath=f.getAbsolutePath().replace("\\", "/");
			File file=getProjctFile(f);
			if(file!=null){
				this.projcetPath=file.getAbsolutePath().replace("\\", "/");
			}
		}
		
		public boolean isApp(){
			return this.isApp;
		}
		
		public void handle(Event t) {
			synchronized (this) {
				if (!luaStatus.isRunning) {
					luaStatus.singleThread = new Thread(new Runnable() {
						public void run() {
							
							luaStatus.getCallback().call(false);// 启动命令

							try{
								if(isApp()){
									
									Job job = new Job(isApp());
									job.pullScript("currProjectPath=function()\n return '"+projcetPath+"'\n end");
									job.pullScript("currFilePath=function()\n return '"+currFilePath+"'\n end");
									if(Events.activeUdids.size()==1){
										
										String udid="";
										for(String k:Events.activeUdids.keySet()){
											udid=k;
											break;
										}
										
										 Varargs varargs = job.getGlobals().get("initDeviceByUdid").invoke(LuaValue.valueOf(udid));
										 int result=varargs.toint(1);
										 
										 if(result==1){
											 job.pullAndRunLua(f.getAbsolutePath());
										 }else if(result==2){
											 System.out.println(mainController.getI18nBundle().getString("select.devics.error"));
										 }else{
											 System.out.println(mainController.getI18nBundle().getString("select.devics.error2"));
										 }
										 
									}else{
										Platform.runLater(new Runnable(){
											public void run(){
												FXMLDialog sdd = mainController.getSelectDeviceDialog();
												sdd.setResizable(false);
												mainController.call(new Callback() {
													@Override
													public Object call(Object param) {
														
														 Varargs varargs = job.getGlobals().get("initDeviceByUdid").invoke(LuaValue.valueOf((String)param));
														 int result=varargs.toint(1);
														 
														 if(result==1){
															 job.pullAndRunLua(f.getAbsolutePath());
														 }else if(result==2){
															 System.out.println(mainController.getI18nBundle().getString("select.devics.error"));
														 }else{
															 System.out.println(mainController.getI18nBundle().getString("select.devics.error2"));
														 }
														return null;
													}
												});
												sdd.show();
											}
										});
										
									}
								
								}else{
									Job job = new Job(isApp());
				
									job.pullScript("currProjectPath=function()\n return '"+projcetPath+"'\n end");
									job.pullScript("currFilePath=function()\n return '"+currFilePath+"'\n end");
									
									job.pullAndRunLua(f.getAbsolutePath());
								}
								
							}catch(Exception e){
								e.printStackTrace();
							}

							luaStatus.getCallback().call(true);// 结束命令
						}
					});
					luaStatus.singleThread.start();
				}
			}
		}
	}
	
	 public File getProjctFile(File f){
		 
		if(f==null||f.getParentFile()==null)return null;
		
		if(mainController.getPath().equals(f.getParentFile().getAbsolutePath())){
			return f;
		}else{
			return getProjctFile(f.getParentFile());
		}
		
	 }
	
	
	

}
